#include <QVBoxLayout>
#include <QSlider>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QFileDialog>
#include <QComboBox>
#include <QFormLayout>
#include <QTableView>
#include <QHeaderView>
#include <QGridLayout>
#include <QMessageBox>
#include <QDir>
#include <QDockWidget>
#include <QListWidget>
#include <QAction>
#include <QMenuBar>
#include <QToolBar>
#include <QStatusBar>
#include <QInputDialog>
#include <QDesktopServices>
#include <QActionGroup>

#include "MainWindow.hxx"
#include "TrackedObject.hxx"
#include "ProjectIO.hxx"
#include "ComboBoxItemDelegate.hxx"
#include "VideoNewDlg.hxx"
#include <QFileSystemModel>
#include <QTreeView>

#include "TreeModel.hxx"
#include "ProjectWizard.hxx"

#include "json.hpp"

using json = nlohmann::json;

json __appSetting;

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
	_isTracking = false;
	_treeModel = 0;
	_treeView = 0;
	_tableView = 0;
	_tableViewModel = 0;
	
	_project = new Project();
	_controller = new VideoController();

    _view = new VideoView();
    _view->setProject(_project);
	_view->setController(_controller);
	_view->setMainWindow(this);

	_controller->setProject(_project);
	_controller->setView(_view);

	_project->setVideoView(_view);

    setCentralWidget(_view);

   createMainMenu();

   setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
   setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);

   createObjectsPanel();
   createTrackerPanel();
   createProjectPanel();
   createPlayerPanel(); 

   statusBar()->showMessage(tr("Status Bar"));

   resize(1920, 760);

   setFocusPolicy(Qt::StrongFocus);
}

MainWindow::~MainWindow()
{
	if (_controller)
	{
		delete _controller;
		_controller = 0;
	}

	if (_project)
	{
		delete _project;
		_project = 0;
	}
}

void MainWindow::updateTimeStamp()
{
	Sequence* sequence = _project->getActiveSequence();
	if (!sequence) return;

	int durationSeconds = (int)(sequence->getVideoDuration()) % 60;
	int durationMinutes = sequence->getVideoDuration() / 60;
	int currentSeconds = (int)(sequence->getCurrentTimestamp()) % 60;
	int currentMinutes = sequence->getCurrentTimestamp() / 60;

	char timeStr[256]; 
	sprintf(timeStr, "TimeStamp:%02d:%02d/%02d:%02d", currentMinutes, currentSeconds, durationMinutes, durationSeconds);

	QString label = QString(timeStr);

	_labelTime->setText(label);

	_slider->setValue(sequence->getCurrentTimestamp() / sequence->getVideoDuration() * 100);
}

void MainWindow::seekVideo(int pos)
{
	Sequence* sequence = _project->getActiveSequence();
	if (!sequence) return;

	double pts = sequence->getVideoDuration() * pos / 99;
	_controller->seekVideoPosition(pts);
}

void MainWindow::openProject()
{
	QString fileName = QFileDialog::getOpenFileName(this,
		tr("Open Project"), ".", tr("Project Files (*.xml *.fprj)"));

	SPDLOG_INFO("Ready to open the project file {}.", fileName.toStdString().c_str());

	if (fileName.length() > 4)
	{
		if (_project)
		{
			if (ProjectIO::LoadProject(_project, fileName.toStdString().c_str()))
			{
				QMessageBox::information(this, "VideoAnnonator", "Load Project Successed!!");
				
				updateActiveSequence();
				updateTable();
				updateTree();
			}
			else
				QMessageBox::information(this, "VideoAnnonator", "Load Project Failed!!");
		}
	}
}

void MainWindow::saveProject()
{
	QString fileName = QFileDialog::getSaveFileName(this,
		tr("Save Project File"), ".", tr("Project Files (*.xml *.fprj)"));

	if (fileName.length() > 4)
	{
		if (_project)
		{
			if (ProjectIO::WriteProject(_project, fileName.toStdString().c_str()))
			{
				SPDLOG_INFO("Save Project File Successed.", fileName.toStdString().c_str());
				QMessageBox::information(this, "VideoAnnonator", "Save Project File Successed!!");
			}
			else
			{
				SPDLOG_INFO("Save Project File failed.");
				QMessageBox::information(this, "VideoAnnonator", "Save Project File failed!!");
			}
		}
	}
	else
	{
		SPDLOG_INFO("Did not set a valid project file to save!. Save Failed.");
		QMessageBox::information(this, "VideoAnnonator", "Do not set a valid project file to save!\r\nSave Failed!!!");
	}		
}

void MainWindow::newProject()
{
	ProjectWizard* wizard = new ProjectWizard();
	wizard->setProject(_project);
	if (wizard->exec() == QDialog::Accepted)
	{
		_controller->playVideo();

		_btnPlay->setText("Pause");

		updateTree();

		goFrameIndex(0);
	}
}

void MainWindow::addSequence()
{
	VideoInfo* vi = new VideoInfo();
	VideoNewDialog vnd;
	vnd.setVideoInfo(vi);

	if (vnd.exec() == QDialog::Accepted)
	{
		Sequence* sequence = new Sequence();
		sequence->setFilePath(vi->VideoFile.toStdString());
		sequence->setId(_project->getNextSequenceId());
		sequence->setName(vi->VideoName.toStdString());
		sequence->setFrameStrip(vi->FrameStrip);
		sequence->setType(SequenceType::VIDEO_SEQUENCE);

		_project->addSequence(sequence);

		SPDLOG_DEBUG("Ready to play the new sequence.");
		
		_controller->playVideo();
		_btnPlay->setText("Pause");
		updateTree();
		goFrameIndex(0);
	}
	else
	{
		delete vi;
	}
}

void MainWindow::removeClass()
{
	if (_project->getClasses()->size() < 2)
	{
		QMessageBox msgBox;
		msgBox.setText("The project at least has one class.");
		msgBox.setInformativeText("You can not remove the last Class!");
		msgBox.setStandardButtons(QMessageBox::Ok);
		int ret = msgBox.exec();
		return;
	}
	QMessageBox msgBox;
	msgBox.setText("The active class will be removed from the project.");
	msgBox.setInformativeText("If you remove this class, all the objects belong to this class will be removed too.\r\nAre you sure to remove the class?");
	msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
	msgBox.setDefaultButton(QMessageBox::Cancel);
	int ret = msgBox.exec();

	if (ret == QMessageBox::Ok)
	{
		_project->removeActiveClass();
		updateTree();
		updateTable();
	}
}

void MainWindow::removeSequence()
{
	if (_project->getSequences()->size() < 2)
	{
		QMessageBox msgBox;
		msgBox.setText("The project at least has one sequence.");
		msgBox.setInformativeText("You can not remove the last sequence!");
		msgBox.setStandardButtons(QMessageBox::Ok);
		int ret = msgBox.exec();

		return;
	}

	QMessageBox msgBox;
	msgBox.setText("The active sequence will be removed from the project.");
	msgBox.setInformativeText("Are you sure to remove the sequence?");
	msgBox.setStandardButtons( QMessageBox::Ok | QMessageBox::Cancel);
	msgBox.setDefaultButton(QMessageBox::Cancel);
	int ret = msgBox.exec();

	if (ret == QMessageBox::Ok)
	{
		_project->removeActiveSequence();
		updateActiveSequence();
		updateTree();
		updateTable();
	}
}

QString getFileNameFromPath(QString filePath)
{
	int lindex = filePath.lastIndexOf("/");
	QString fileName = filePath.right(filePath.length() - lindex - 1);
	return fileName.left(fileName.length() - 4);
}

void MainWindow::exportYOLODataset()
{
	QString targetDir = QFileDialog::getExistingDirectory(this, tr("Export Project To Directory"));

	if (targetDir.length() >= 3)
	{
		QDir dir(targetDir);

		if (dir.exists())
		{
			QString imageDir;

			QString prjName = _project->getName().c_str();

			if (targetDir.at(targetDir.length() - 1) == QChar('/'))
				imageDir = targetDir.append(prjName);
			else
				imageDir = targetDir.append("/").append(prjName);

			dir.mkdir(imageDir);

			_controller->pauseVideo();
			_btnPlay->setText("Play");

            ProjectIO::ExportProject(this,_project, imageDir.toStdString().c_str());
		}
	}
}

void MainWindow::exportFishDataset()
{
	QString targetDir = QFileDialog::getExistingDirectory(this, tr("Export Project To Directory"));

	if (targetDir.length() >= 3)
	{
		QDir dir(targetDir);

		if (dir.exists())
		{
			QString imageDir;

			//QString dirName = getFileNameFromPath(_model->getFilePath().c_str());
			QString prjName = _project->getName().c_str();

			if (targetDir.at(targetDir.length() - 1) == QChar('/'))
				imageDir = targetDir.append(prjName);
			else
				imageDir = targetDir.append("/").append(prjName);

			dir.mkdir(imageDir);

			_controller->pauseVideo();
			_btnPlay->setText("Play");

			ProjectIO::ExportFishProject(this, _project, imageDir.toStdString().c_str());

		}
	}
}

void MainWindow::playOrPauseVideo()
{
	if (_btnPlay->text().compare("Pause") == 0)
	{
		pauseVideo();
	}
	else
	{
		playVideo();
	}
}

void MainWindow::playVideo()
{
	_controller->resumeVideo();
	_btnPlay->setText("Pause");
	_actPlay->setEnabled(false);
	_actPause->setEnabled(true);
}

void MainWindow::pauseVideo()
{
	_controller->pauseVideo();
	_btnPlay->setText("Play");
	_actPlay->setEnabled(true);
	_actPause->setEnabled(false);
}

void MainWindow::goTime()
{
	QString valstr = _linTargetTime->text();
	char valchr[256];
	
	strcpy(valchr, valstr.toLatin1());

	int hours = 0;
	int minutes = 0;
	int seconds = 0;

	sscanf(valchr, "%02d:%02d:%02d", &hours, &minutes, &seconds);

	int targetTime = hours* 3600 + minutes * 60 + seconds;

	_controller->seekVideoPosition(targetTime);
}

void MainWindow::goFrame()
{
	if (!_project) return;

	Sequence* sequence = _project->getActiveSequence();
	if (!sequence) return;

	QString valstr = _linTargetFrame->text();
	int findex;

	sscanf(valstr.toLatin1(), "%d", &findex);

	if (findex % sequence->getFrameStrip() != 0)
	{
		findex = int(findex / sequence->getFrameStrip()) * sequence->getFrameStrip();
		valstr = QString("%1").arg(findex);
		_linTargetFrame->setText(valstr);
	}


	goFrameIndex(findex);
}

void MainWindow::goFrameIndex(int findex)
{
	if (!_project->getActiveSequence())
		return;

	_controller->fast();
	_controller->resumeVideo();
	//_controller->seekVideoPosition(pts);
	_controller->seekVideoPosition(findex);
	_controller->actionGoFrame(findex);

	_btnPlay->setText("Play");
}

void MainWindow::clearRects()
{
	if (_view)
	{
		_view->clearRects();
		_view->update();

		_btnStartTrack->setEnabled(false);
		_actStartTrack->setEnabled(false);

		_btnClearRects->setEnabled(false);
		_actClearRect->setEnabled(false);

		_btnRects2Objects->setEnabled(false);
		_actRects2Objects->setEnabled(false);

		_btnSingleFrameObjects->setEnabled(false);
		//unSelectRect();
	}
}

void MainWindow::startTrack()
{
	if (!_isTracking)
	{
		if (_controller)
		{
			_controller->startTrack(_comboBox->currentText().toLatin1(),_cbNetModel->currentText().toLatin1());

			_controller->resumeVideo();
			_btnPlay->setText("Pause");
			_btnStartTrack->setText("Stop Track");
			_actStartTrack->setText("Stop Track");
			//_btnStopTrack->setEnabled(true);
			//_actStopTrack->setEnabled(true);

			//_btnStartTrack->setEnabled(false);
			//_actStartTrack->setEnabled(false);

			_btnStartTrack->setEnabled(true);
			_actStartTrack->setEnabled(true);

			_btnClearRects->setEnabled(false);
			_actClearRect->setEnabled(false);

			_btnRects2Objects->setEnabled(false);
			_actRects2Objects->setEnabled(false);

			_btnSingleFrameObjects->setEnabled(false);

			_isTracking = true;
		}
	}
	else
	{
		stopTrack();
		_isTracking = false;
	}
}

void MainWindow::stopTrack()
{
	if (_controller)
	{
		pauseVideo();

		_controller->stopTrack();

		updateTable();
		updateTree();
		
		if (_comboBox->currentIndex() > 1)
		{
			_btnStartTrack->setText("Start Track");
			_btnStartTrack->setEnabled(false);
			_actStartTrack->setText("Start Track");
			_actStartTrack->setEnabled(false);
		}
		else
		{
			_btnStartTrack->setText("Start Track");
			_btnStartTrack->setEnabled(true);
			_actStartTrack->setText("Start Track");
			_actStartTrack->setEnabled(true);
		}

		
		//_btnStopTrack->setEnabled(false);
		//_actStopTrack->setEnabled(false);
	}
}

void MainWindow::slowDown()
{
	if (_btnSlow->text().compare("Slow") == 0)
	{
		_controller->slow();
		_btnSlow->setText("Fast");
	}
	else
	{
		_controller->fast();
		_btnSlow->setText("Slow");
	}
}

void MainWindow::deleteObject()
{
	if (!_project->getActiveSequence())
		return;

	Sequence* sequence = _project->getActiveSequence();

	if (sequence)
	{
		sequence->deleteSelectedObject();

		updateTable();

		_view->update();

		unSelectObject();
	}
}

void MainWindow::startObject()
{
	if (!_project->getActiveSequence())
		return;

	Sequence* sequence = _project->getActiveSequence();

	if (sequence)
	{
		sequence->startObject(_view->getCurrentFrameIndex());

		updateTable();

		_view->update();
	}
}

void MainWindow::makeSingleFrameObjects()
{
	if (_controller)
	{
		_controller->makeSingleFrameObjects();
		_view->update();
		updateTable();
		updateTree();
	}
}

void MainWindow::endObject()
{
	if (!_project->getActiveSequence())
		return;

	Sequence* sequence = _project->getActiveSequence();

	if (sequence)
	{
		sequence->endObject(_view->getCurrentFrameIndex());

		updateTable();

		_view->update();
	}
}

void MainWindow::nextFrame()
{
	if (_controller)
		_controller->nextFrame();
}

void MainWindow::prevFrame()
{
	if (!_project->getActiveSequence())
		return;

	int findex = _view->getCurrentFrameIndex();

	if (findex > 0)
		findex -= _project->getActiveSequence()->getFrameStrip();

	int tindex = findex;

	if (tindex > 50)
		tindex = tindex - 50;
	else
		tindex = 0;

	Sequence* sequence = _project->getActiveSequence();

	double pts = tindex / sequence->getFrameRate();

	_controller->fast();
	_controller->resumeVideo();
	_controller->seekVideoPosition(pts);
	_controller->actionGoFrame(findex);
}

QLayout* MainWindow::createPanelLayout()
{
	QVBoxLayout* layout = new QVBoxLayout();

	QGridLayout* projectLayout = new QGridLayout();

	QPushButton* btnOpen = new QPushButton("Open");
	QPushButton* btnNew = new QPushButton("New");
	QPushButton* btnSave = new QPushButton("Save");
	QPushButton* btnExport = new QPushButton("Export");

	projectLayout->addWidget(btnOpen, 0, 0);
	projectLayout->addWidget(btnNew, 0, 1);
	projectLayout->addWidget(btnSave, 1, 0);
	projectLayout->addWidget(btnExport, 1, 1);

	layout->addLayout(projectLayout);

	connect(btnOpen, SIGNAL(clicked()), this, SLOT(openProject()));
	connect(btnSave, SIGNAL(clicked()), this, SLOT(saveProject()));
	connect(btnNew, SIGNAL(clicked()), this, SLOT(newProject()));
	connect(btnExport, SIGNAL(clicked()), this, SLOT(exportProject()));

	return layout;
}

void MainWindow::updateFrameInfo()
{
	if (_view)
	{
		_labelFrame->setText(QString("Frame Index:%1").arg(_view->getCurrentFrameIndex()));
	}
}

#define CLASS_DATA_ROLE	(Qt::UserRole + 10)

void MainWindow::updateTable()
{
	if (!_project->getActiveSequence())
		return;

	Sequence* sequence = _project->getActiveSequence();

    // update table view
	std::vector<TrackedObject*>* objects = sequence->getTrackedObjects();
	
	_tableViewModel->removeRows(0, _tableViewModel->rowCount());

	for (int i = 0; i < objects->size(); i++)
	{
		TrackedObject* object = objects->at(i);
		
		QStandardItem* idItem = new QStandardItem(QString("%1").arg(object->getObjectId()));
		idItem->setFlags(idItem->flags() & (~Qt::ItemIsEditable));

		QVariant iData;
		iData.setValue(object);

		idItem->setData(iData);

		_tableViewModel->setItem(i, 0, idItem);
		_tableViewModel->item(i, 0)->setTextAlignment(Qt::AlignCenter);

        // Find Class Name for the Object;
        int cindex = object->getClassIndex();
		std::vector<Class*>* classes = _project->getClasses();

		for(int j = 0; j < classes->size(); j ++)
        {
            Class* cls = classes->at(j);
            if(cls->getId() == cindex)
            {
                QStandardItem* classItem = new QStandardItem(cls->getName().c_str());
                QVariant data;
                data.setValue<int>( cindex );

                classItem->setData(data,Qt::UserRole);
                _tableViewModel->setItem(i,1,classItem);

                break;
            }
        }

        _tableViewModel->setItem(i, 2, new QStandardItem(QString("%1").arg(object->getStartFrameIndex())));
        _tableViewModel->item(i, 2)->setTextAlignment(Qt::AlignCenter);
        _tableViewModel->setItem(i, 3, new QStandardItem(QString("%1").arg(object->getEndFrameIndex())));
        _tableViewModel->item(i, 3)->setTextAlignment(Qt::AlignCenter);
	}
}

void MainWindow::selectObject()
{
	_btnDeleteObject->setEnabled(true);
	_actDeleteObject->setEnabled(true);

	_btnStartTrack->setEnabled(false);
	_btnStartTrack->setEnabled(false);

	_btnRects2Objects->setEnabled(false);
	_actRects2Objects->setEnabled(false);

	_btnClearRects->setEnabled(false);
	_actClearRect->setEnabled(false);

	_btnEndObject->setEnabled(true);
	_actEndObject->setEnabled(true);

	_btnHideSelectedObjects->setEnabled(true);
	_btnHideUnSelectedObjects->setEnabled(true);

	_actHideSelectedObjects->setEnabled(true);
	_actHideUnSelectedObjects->setEnabled(true);

	updateSelectedTableRows();
}

void MainWindow::unSelectObject()
{
	_btnDeleteObject->setEnabled(false);
	_actDeleteObject->setEnabled(false);

	_btnStartObject->setEnabled(false);
	_actStartObject->setEnabled(false);

	_btnEndObject->setEnabled(false);
	_actEndObject->setEnabled(false);

	_btnHideSelectedObjects->setEnabled(false);
	_actHideSelectedObjects->setEnabled(false);

	_btnHideUnSelectedObjects->setEnabled(false);
	_actHideUnSelectedObjects->setEnabled(false);

	updateSelectedTableRows();
}

void MainWindow::selectRect()
{
	_btnStartTrack->setEnabled(true);
	_actStartTrack->setEnabled(true);

	_btnClearRects->setEnabled(true);
	_actClearRect->setEnabled(true);

	_btnRects2Objects->setEnabled(true);
	_actRects2Objects->setEnabled(true);

	_btnSingleFrameObjects->setEnabled(true);
}

//void MainWindow::unSelectRect()
//{
//	_btnStartTrack->setEnabled(false);
//	_actStartTrack->setEnabled(false);
//
//	_btnClearRects->setEnabled(false);
//	_actClearRect->setEnabled(false);
//
//	_btnRects2Objects->setEnabled(false);
//	_actRects2Objects->setEnabled(false);
//
//	_btnSingleFrameObjects->setEnabled(false);
//}

void MainWindow::tableDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
   int startRow = topLeft.row();
   int startCol = topLeft.column();

   int endRow = bottomRight.row();
   int endCol = topLeft.column();

   //if (startCol > 1 || endCol < 1)
	  // return;

   if (!_project->getActiveSequence())
	   return;

   Sequence* sequence = _project->getActiveSequence();


   for(int row = startRow; row <= endRow; row++)
   {
       QModelIndex cellId = _tableViewModel->index(row,0);
       QModelIndex cellClass = _tableViewModel->index(row,1);
	   QModelIndex cellStart = _tableViewModel->index(row, 2);
	   QModelIndex cellEnd = _tableViewModel->index(row, 3);

       int objectId = cellId.data().toInt();
       int classIndex = cellClass.data(Qt::UserRole).toInt();
	   int startFrame = cellStart.data().toInt();
	   int endFrame = cellEnd.data().toInt();

	   for (int col = startCol; col <= endCol; col++)
	   {
		   if (col == 1)
			   sequence->updateObjectClass(objectId, classIndex);
		   else if (col == 2)
			   sequence->updateObjectStartFrame(objectId, startFrame);
		   else if (col == 3)
			   sequence->updateObjectEndFrame(objectId, endFrame);
	   }	   
   }

   _view->update();
}

void MainWindow::tableRowClicked(const QModelIndex& index)
//void MainWindow::tableRowActivated(const QModelIndex& index)
{
	int row = index.row();

	//_tableView->clearSelection();

	//_tableView->selectRow(row);

	QStandardItem* item = _tableViewModel->item(row, 0);

	QVariant data = item->data();

	TrackedObject* selectedObject = data.value<TrackedObject*>();

	if (!selectedObject->isSelected())
		selectedObject->select();

	// deselect all other objects;
	Sequence* sequence = _project->getActiveSequence();

	std::vector<TrackedObject*>* objs = sequence->getTrackedObjects();

	for (int i = 0; i < objs->size(); i++)
	{
		TrackedObject* obj = objs->at(i);
		if (selectedObject != obj)
			obj->deselect();
	}

	QItemSelectionModel* model = _tableView->selectionModel();
	QModelIndexList list = model->selectedRows();
	if (list.size() > 1)
	{
		_btnMergeObjects->setEnabled(true);
		_actMergeObject->setEnabled(true);
	}
	else
	{
		_btnMergeObjects->setEnabled(false);
		_actMergeObject->setEnabled(false);
	}

	_view->update();
}

void MainWindow::createMainMenu()
{
	////////////////// Project Menu ////////////////////////////////
	QMenu* projectMenu = menuBar()->addMenu(tr("&Project"));
	QToolBar* projectToolBar = addToolBar(tr("Project"));
	QToolBar* zoomToolBar = addToolBar(tr("Zoom"));

    const QIcon newIcon = QIcon(":/images/new.png");
    const QIcon openIcon = QIcon(":/images/open.png");
    const QIcon saveIcon = QIcon(":/images/save.png");
    const QIcon closeIcon = QIcon(":/images/close.png");
    const QIcon addIcon = QIcon(":/images/add.png");
    const QIcon subIcon = QIcon(":/images/sub.png");
    const QIcon exportIcon = QIcon(":/images/export.png");

	//const QIcon zoomArrowIcon = QIcon(":/images/mouse.png");
	//const QIcon zoomDragIcon = QIcon(":/images/drag.png");
	const QIcon zoomInIcon = QIcon(":/images/zoomin.png");
	const QIcon zoomFitIcon = QIcon(":/images/zoomfit.png");
	const QIcon zoomOutIcon = QIcon(":/images/zoomout.png");
	const QIcon zoomFullScreenIcon = QIcon(":/images/fullscreen.png");

	QAction* newProjectAct = new QAction(newIcon, tr("&New Project..."), this);
	newProjectAct->setShortcuts(QKeySequence::New);
	newProjectAct->setStatusTip(tr("Create a new project."));
	connect(newProjectAct, &QAction::triggered, this, &MainWindow::newProject);

    QAction* openProjectAct = new QAction(openIcon, tr("&Open Project..."), this);
	openProjectAct->setShortcuts(QKeySequence::Open);
	openProjectAct->setStatusTip(tr("Open a project."));
	connect(openProjectAct, &QAction::triggered, this, &MainWindow::openProject);

    QAction* saveProjectAct = new QAction(saveIcon, tr("&Save Project"), this);
	saveProjectAct->setShortcuts(QKeySequence::Save);
	saveProjectAct->setStatusTip(tr("Save the edited project."));
	connect(saveProjectAct, &QAction::triggered, this, &MainWindow::saveProject);

    QAction* closeProjectAct = new QAction(closeIcon, tr("&Close Project"), this);
	closeProjectAct->setShortcuts(QKeySequence::Close);
	closeProjectAct->setStatusTip(tr("Close project."));

    QAction* exportYOLOProjectAct = new QAction(exportIcon, tr("&Export YOLO Dataset..."), this);
	exportYOLOProjectAct->setStatusTip(tr("Export YOLO Dataset ..."));
	connect(exportYOLOProjectAct, &QAction::triggered, this, &MainWindow::exportYOLODataset);

	QAction* exportFishProjectAct = new QAction(exportIcon, tr("&Export Fish Dataset..."), this);
	exportFishProjectAct->setStatusTip(tr("Export project."));
	connect(exportFishProjectAct, &QAction::triggered, this, &MainWindow::exportFishDataset);

	QAction* importProjectAct = new QAction(exportIcon, tr("&Import Project..."), this);
	importProjectAct->setStatusTip(tr("Import project."));
	connect(importProjectAct, &QAction::triggered, this, &MainWindow::importProject);

	//connect(newLetterAct, &QAction::triggered, this, &MainWindow::newLetter);
	projectMenu->addAction(newProjectAct);
	projectMenu->addAction(openProjectAct);
	projectMenu->addAction(saveProjectAct);
	projectMenu->addAction(closeProjectAct);
	projectMenu->addSeparator();

	projectMenu->addSeparator();


	projectMenu->addAction(importProjectAct);
	QMenu* exportMenu = projectMenu->addMenu(tr("Export"));
	exportMenu->addAction(exportYOLOProjectAct);
	exportMenu->addAction(exportFishProjectAct);


	projectToolBar->addAction(newProjectAct);
	projectToolBar->addAction(openProjectAct);
	projectToolBar->addAction(saveProjectAct);
	projectToolBar->addAction(closeProjectAct);
    projectToolBar->addAction(exportYOLOProjectAct);
	projectToolBar->addAction(exportFishProjectAct);
    projectToolBar->addSeparator();
	//projectToolBar->addAction(addSequenceAct);
	//projectToolBar->addAction(removeSequenceAct);

	projectMenu->addSeparator();

	QAction* quitAct = projectMenu->addAction(tr("&Quit"), this, &QWidget::close);
	quitAct->setShortcuts(QKeySequence::Quit);
	quitAct->setStatusTip(tr("Quit the application"));

	/////////////////// Edit Menu  ////////////////////////////////////////////////////
	QMenu* editMenu = menuBar()->addMenu(tr("Edit"));

	QAction* addSequenceAct = new QAction(addIcon, tr("&Add Sequence..."), this);
	addSequenceAct->setStatusTip(tr("Add a sequence for the current project."));
	connect(addSequenceAct, &QAction::triggered, this, &MainWindow::addSequence);

	QAction* removeSequenceAct = new QAction(subIcon, tr("&Remove Sequence"), this);
	removeSequenceAct->setStatusTip(tr("Remove the active sequence for the current project."));
	connect(removeSequenceAct, &QAction::triggered, this, &MainWindow::removeSequence);

	QAction* importSequencesAct = new QAction(addIcon, tr("&Import Sequences..."), this);
	importSequencesAct->setStatusTip(tr("Import Sequences and Classes from a exist project."));
	connect(importSequencesAct, &QAction::triggered, this, &MainWindow::importSequences);

	QAction* addClassAct = new QAction(addIcon, tr("&Add Class"), this);
	addSequenceAct->setStatusTip(tr("Add a class for the current project."));
	connect(addClassAct, &QAction::triggered, this, &MainWindow::addClass);
	
	QAction* removeClassAct = new QAction(subIcon, tr("&Remove Class"), this);
	removeSequenceAct->setStatusTip(tr("Remove the active class for the current project."));
	connect(removeClassAct, &QAction::triggered, this, &MainWindow::removeClass);
	
	editMenu->addAction(addSequenceAct);
	editMenu->addAction(importSequencesAct);
	editMenu->addAction(removeSequenceAct);
	editMenu->addSeparator();
	editMenu->addAction(addClassAct);
	editMenu->addAction(removeClassAct);

	/////////////////// Sequence Menu /////////////////////////////////////////////////
    const QIcon playIcon = QIcon(":/images/play.png");
    const QIcon pauseIcon = QIcon(":/images/pause.png");
    const QIcon stopIcon = QIcon(":/images/stop.png");
    const QIcon slowIcon = QIcon(":/images/slow.png");
    const QIcon fastIcon = QIcon(":/images/fast.png");

	QMenu* sequenceMenu = menuBar()->addMenu(tr("&Sequence"));
	QToolBar* sequenceToolBar = addToolBar(tr("Sequence"));

    _actPlay = new QAction(playIcon, tr("&Play"), this);
	_actPlay->setStatusTip(tr("Play the active sequence."));
	_actPlay->setShortcut(QKeySequence(tr("A")));

    _actPause = new QAction(pauseIcon, tr("&Pause"), this);
	_actPause->setStatusTip(tr("Pause the active sequence."));
	_actPause->setShortcut(QKeySequence(tr("S")));

    _actPreviousFrame = new QAction(slowIcon, tr("&Previous Frame"), this);
	_actPreviousFrame->setStatusTip(tr("Go to previous frame."));
	_actPreviousFrame->setShortcut(QKeySequence(tr("K")));

    _actNextFrame = new QAction(fastIcon, tr("&Next Frame"), this);
	_actNextFrame->setStatusTip(tr("Go to the next frame."));
	_actNextFrame->setShortcut(QKeySequence(tr("L")));

	connect(_actPlay, &QAction::triggered, this, &MainWindow::playOrPauseVideo);
	connect(_actPause, &QAction::triggered, this, &MainWindow::playOrPauseVideo);
	connect(_actPreviousFrame, &QAction::triggered, this, &MainWindow::prevFrame);
	connect(_actNextFrame, &QAction::triggered, this, &MainWindow::nextFrame);

	//connect(undoAct, &QAction::triggered, this, &MainWindow::undo);
	sequenceMenu->addAction(_actPlay);
	sequenceMenu->addAction(_actPause);
	sequenceMenu->addSeparator();
	sequenceMenu->addAction(_actPreviousFrame);
	sequenceMenu->addAction(_actNextFrame);

	sequenceToolBar->addAction(_actPreviousFrame);
	sequenceToolBar->addAction(_actPlay);
	sequenceToolBar->addAction(_actPause);
	sequenceToolBar->addAction(_actNextFrame);

	////////////////// Tracker Menu  ///////////////////////////////////////////////////
	QMenu* trackerMenu = menuBar()->addMenu(tr("&Tracker"));

	_actStartTrack = trackerMenu->addAction(tr("Start Track"));
	_actStartTrack->setEnabled(false);

	//_actStopTrack = trackerMenu->addAction(tr("Stop Track"));
	//_actStopTrack->setEnabled(false);
	_actRects2Objects = trackerMenu->addAction(tr("Rects to Objects"));
	_actRects2Objects->setEnabled(false);

	_actClearRect = trackerMenu->addAction(tr("Clear Rects"));
	_actClearRect->setEnabled(false);

	trackerMenu->addSeparator();

	_actStartObject = trackerMenu->addAction(tr("Start Object"));
	_actStartObject->setEnabled(false);

	_actEndObject = trackerMenu->addAction(tr("End Object"));
	_actEndObject->setEnabled(false);

	_actMergeObject = trackerMenu->addAction(tr("Merge Object"));
	_actMergeObject->setEnabled(false);

	_actDeleteObject = trackerMenu->addAction(tr("Delete Object"));
	_actDeleteObject->setEnabled(false);

	trackerMenu->addSeparator();

	_actHideSelectedObjects = trackerMenu->addAction(tr("Hide Selected Object"));
	_actHideSelectedObjects->setEnabled(false);

	_actHideUnSelectedObjects = trackerMenu->addAction(tr("Hide UnSelected Object"));
	_actHideUnSelectedObjects->setEnabled(false);

	_actShowAllObjects = trackerMenu->addAction(tr("Show All Objects"));
	_actShowAllObjects->setEnabled(false);

	_actSingleFrameObjects = trackerMenu->addAction(tr("Single Frame Object"));
	_actSingleFrameObjects->setEnabled(false);

	_actNegativeSampleFrame = trackerMenu->addAction(tr("Negative Sample Object"));

	connect(_actStartTrack, &QAction::triggered, this, &MainWindow::startTrack);
	//connect(_actStopTrack, &QAction::triggered, this, &MainWindow::stopTrack);
	connect(_actClearRect, &QAction::triggered, this, &MainWindow::clearRects);
	connect(_actMergeObject, &QAction::triggered, this, &MainWindow::mergeSelectedObjects);
	connect(_actDeleteObject, &QAction::triggered, this, &MainWindow::deleteObject);
	connect(_actStartObject, &QAction::triggered, this, &MainWindow::startObject);
	connect(_actEndObject, &QAction::triggered, this, &MainWindow::endObject);

	connect(_actHideSelectedObjects, &QAction::triggered, this, &MainWindow::hideSelectedObjects);
	connect(_actHideUnSelectedObjects, &QAction::triggered, this, &MainWindow::hideUnSelectedObjects);
	connect(_actShowAllObjects, &QAction::triggered, this, &MainWindow::showAllObjects);
	connect(_actSingleFrameObjects, &QAction::triggered, this, &MainWindow::makeSingleFrameObjects);
	connect(_actNegativeSampleFrame, &QAction::triggered, this, &MainWindow::makeNegativeSampleFrame);


	menuBar()->addSeparator();
	/////////////////Docker Menu/////////////////////////////////////////////////////////
	_dockerMenu = menuBar()->addMenu(tr("Window"));

	////////////////// Help Menu ///////////////////////////////////////////////////////
	QMenu* helpMenu = menuBar()->addMenu(tr("&Help"));
	QAction* helpAct = helpMenu->addAction(tr("&Help"), this, &MainWindow::help);
	QAction* aboutAct = helpMenu->addAction(tr("&About"), this, &MainWindow::about);
	//aboutAct->setStatusTip(tr("Show the application's About box"));

	//QAction* aboutQtAct = helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
	//aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));

	//QAction* zoomDragAct = new QAction(zoomDragIcon, tr("&Drag"), this);
	//zoomDragAct->setCheckable(true);
	//zoomDragAct->setChecked(false);
	//zoomDragAct->setStatusTip(tr("Drag the frame."));

	//QAction* zoomArrowAct = new QAction(zoomArrowIcon, tr("&Arrow"), this);
	//zoomArrowAct->setCheckable(true);
	//zoomArrowAct->setChecked(true);
	//zoomArrowAct->setStatusTip(tr("You can interactive select object with rectangle."));

	QAction* zoomInAct = new QAction(zoomInIcon, tr("&Zoom In"), this);
	zoomInAct->setStatusTip(tr("Zoom in the frame."));

	QAction* zoomFitAct = new QAction(zoomFitIcon, tr("&Zoom Fit"), this);
	zoomFitAct->setStatusTip(tr("Zoom fit the frame."));

	QAction* zoomOutAct = new QAction(zoomOutIcon, tr("&Zoom Out"), this);
	zoomOutAct->setStatusTip(tr("Zoom out the frame."));

	QAction* zoomFullScreenAct = new QAction(zoomFullScreenIcon, tr("&Zoom Out"), this);
	zoomFullScreenAct->setStatusTip(tr("Fullscreen the view."));
	//_actPlay->setShortcut(QKeySequence(tr("A")));

	//connect(zoomArrowAct, &QAction::triggered, this, &MainWindow::zoomArrow);
	//connect(zoomDragAct, &QAction::triggered, this, &MainWindow::zoomDrag);
	connect(zoomInAct, &QAction::triggered, this, &MainWindow::zoomIn);
	connect(zoomFitAct, &QAction::triggered, this, &MainWindow::zoomFit);
	connect(zoomOutAct, &QAction::triggered, this, &MainWindow::zoomOut);
	connect(zoomFullScreenAct, &QAction::triggered, this, &MainWindow::zoomFullScreen);

	//QActionGroup* agroup = new QActionGroup(zoomToolBar);
	//agroup->addAction(zoomArrowAct);
	//agroup->addAction(zoomDragAct);

	//zoomToolBar->addAction(zoomArrowAct);
	//zoomToolBar->addAction(zoomDragAct);
	zoomToolBar->addAction(zoomInAct);
	zoomToolBar->addAction(zoomFitAct);
	zoomToolBar->addAction(zoomOutAct);
	zoomToolBar->addAction(zoomFullScreenAct);
}

void MainWindow::createObjectsPanel()
{
	QDockWidget* dock = new QDockWidget(tr("Objects"), this);
	dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);

	_dockerMenu->addAction(dock->toggleViewAction());

	QVBoxLayout* objectsLayout = new QVBoxLayout();

	QLabel* tableLabel = new QLabel("Tracked Object:");
	objectsLayout->addWidget(tableLabel);

	_tableViewModel = new QStandardItemModel();

	connect(_tableViewModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)),
		this, SLOT(tableDataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));

	

	QStringList headers;
	headers.append("Object ID");
	headers.append("Object Class");
	headers.append("Start Frame");
	headers.append("End Frame");

	_tableViewModel->setHorizontalHeaderLabels(headers);

	_tableView = new QTableView();
	_tableView->setModel(_tableViewModel);

	ComboBoxItemDelegate* cbid = new ComboBoxItemDelegate(_tableView);
	cbid->setProject(_project);

	_tableView->setItemDelegateForColumn(1, cbid);

	_tableView->setSortingEnabled(false);
	_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
	_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
	_tableView->setSelectionMode(QAbstractItemView::MultiSelection);
	_tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	_tableView->setShowGrid(true);
	_tableView->horizontalHeader()->setStretchLastSection(true);
	_tableView->verticalHeader()->hide();
	_tableView->setColumnWidth(0, 80);
	_tableView->setColumnWidth(1, 100);
	_tableView->setColumnWidth(2, 100);
	_tableView->setColumnWidth(3, 100);
	_tableView->setEditTriggers(QAbstractItemView::DoubleClicked);
	_tableView->setMinimumWidth(240);

	//connect(_tableView, SIGNAL(activated(const QModelIndex&)), this, SLOT(tableRowActivated(const QModelIndex&)));
	connect(_tableView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(tableRowClicked(const QModelIndex&)));
	objectsLayout->addWidget(_tableView);

	QWidget* objectsWidget = new QWidget(dock);

	objectsLayout->setMargin(5);

	objectsWidget->setLayout(objectsLayout);
	dock->setWidget(objectsWidget);
	addDockWidget(Qt::RightDockWidgetArea, dock);
}

void MainWindow::createTrackerPanel()
{
	_comboBox = new QComboBox();
	_comboBox->addItem("SORTTracker");
	_comboBox->addItem("YOLODetector");
	_comboBox->addItem("CSRT");
	_comboBox->addItem("MOSSE");
	_comboBox->addItem("GOTURN");
	_comboBox->addItem("KCF");
	_comboBox->addItem("TLD");
	_comboBox->addItem("MedianFlow");
	_comboBox->addItem("Boosting");
	_comboBox->addItem("MIL");

	std::ifstream f("VideoAnnotator.json");
	__appSetting = json::parse(f);

	_cbNetModel = new QComboBox();
	for (auto& tracker : __appSetting["trackers"]) {
		std::string val = tracker["name"];
		_cbNetModel->addItem(QString::fromStdString(val));
	}

	QFormLayout* formLayout = new QFormLayout();
	formLayout->addRow("Tracker:", _comboBox);
	formLayout->addRow("Model:", _cbNetModel);

	QGridLayout* gridLayout = new QGridLayout();

	_btnStartTrack = new QPushButton("Start Track");
	_btnStartTrack->setEnabled(true);
	_btnRects2Objects = new QPushButton("Rects to Objects");
	_btnRects2Objects->setEnabled(false);
	//_btnStopTrack = new QPushButton("Stop Track");
	//_btnStopTrack->setEnabled(false);

	_btnClearRects = new QPushButton("Clear Rects");
	_btnClearRects->setEnabled(false);

	_btnMergeObjects = new QPushButton("Merge Objects");
	_btnMergeObjects->setEnabled(false);

	_btnHideUnSelectedObjects = new QPushButton("Hide UnSelected Objects");
	_btnHideUnSelectedObjects->setEnabled(false);

	_btnHideSelectedObjects = new QPushButton("Hide Selected Objects");
	_btnHideSelectedObjects->setEnabled(false);

	_btnSingleFrameObjects = new QPushButton("Signel Frame Objects");
	_btnSingleFrameObjects->setEnabled(false);

	_btnNegativeSampleFrame = new QPushButton("Negative Sample Frame");
	_btnNegativeSampleFrame->setEnabled(true);

	_btnShowAllObjects = new QPushButton("Show All Objects");
	_btnShowAllObjects->setEnabled(false);

	_btnDeleteObject = new QPushButton("Delete Object");
	_btnStartObject = new QPushButton("Start Object");
	_btnEndObject = new QPushButton("End Object");

	_btnDeleteObject->setEnabled(false);
	_btnStartObject->setEnabled(false);
	_btnEndObject->setEnabled(false);


	QPushButton* btnPrevious = new QPushButton("Previous Frame");
	QPushButton* btnNext = new QPushButton("Next Frame");

	connect(_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(trackTypeChanged(int)));

	connect(_btnClearRects, SIGNAL(clicked()), this, SLOT(clearRects()));
	connect(_btnStartTrack, SIGNAL(clicked()), this, SLOT(startTrack()));
	//connect(_btnStopTrack, SIGNAL(clicked()), this, SLOT(stopTrack()));
	connect(_btnRects2Objects, SIGNAL(clicked()), this, SLOT(rects2Objects()));

	connect(_btnStartObject, SIGNAL(clicked()), this, SLOT(startObject()));
	connect(_btnEndObject, SIGNAL(clicked()), this, SLOT(endObject()));
	connect(_btnMergeObjects, SIGNAL(clicked()), this, SLOT(mergeSelectedObjects()));
	connect(_btnSingleFrameObjects, SIGNAL(clicked()), this, SLOT(makeSingleFrameObjects()));
	connect(_btnNegativeSampleFrame, SIGNAL(clicked()), this, SLOT(makeNegativeSampleFrame()));

	connect(btnNext, SIGNAL(clicked()), this, SLOT(nextFrame()));
	connect(btnPrevious, SIGNAL(clicked()), this, SLOT(prevFrame()));

	connect(_btnDeleteObject, SIGNAL(clicked()), this, SLOT(deleteObject()));

	connect(_btnHideSelectedObjects, SIGNAL(clicked()), this, SLOT(hideSelectedObjects()));
	connect(_btnHideUnSelectedObjects, SIGNAL(clicked()), this, SLOT(hideUnSelectedObjects()));
	connect(_btnShowAllObjects, SIGNAL(clicked()), this, SLOT(showAllObjects()));

	connect(_view, SIGNAL(frameInfoUpdated()), this, SLOT(updateFrameInfo()));
	connect(_view, SIGNAL(objectSelected()), this, SLOT(selectObject()));
	connect(_view, SIGNAL(objectUnSelected()), this, SLOT(unSelectObject()));
	connect(_view, SIGNAL(rectAdded()), this, SLOT(selectRect()));
	//connect(_view, SIGNAL(rectUnSelected()), this, SLOT(unSelectRect()));

	gridLayout->addWidget(_btnStartTrack, 0, 0);
	gridLayout->addWidget(_btnRects2Objects, 0, 1);

	gridLayout->addWidget(_btnMergeObjects,1, 0);
	gridLayout->addWidget(_btnDeleteObject, 1, 1);
	gridLayout->addWidget(_btnStartObject, 2, 0);
	gridLayout->addWidget(_btnEndObject, 2, 1);


	gridLayout->addWidget(_btnHideUnSelectedObjects, 3, 0);
	gridLayout->addWidget(_btnHideSelectedObjects, 3, 1);

	gridLayout->addWidget(_btnShowAllObjects, 4, 0);
	gridLayout->addWidget(_btnClearRects, 4, 1);

	gridLayout->addWidget(_btnSingleFrameObjects, 5, 0);
	gridLayout->addWidget(_btnNegativeSampleFrame, 5, 1);
	

	gridLayout->addWidget(btnNext, 6, 0);
	gridLayout->addWidget(btnPrevious, 6, 1);

	QVBoxLayout* layout = new QVBoxLayout();

	formLayout->setMargin(25);
	layout->addLayout(formLayout);
	layout->addLayout(gridLayout);

	QWidget* trackerWidget = new QWidget();
	
	//trackerWidget->setMaximumWidth(350);
	trackerWidget->setMinimumWidth(300);
	trackerWidget->setMinimumHeight(200);
	trackerWidget->setLayout(layout);

	QDockWidget* trackerDocker = new QDockWidget(tr("Tracker"),this);
	trackerDocker->setWidget(trackerWidget);
	addDockWidget(Qt::RightDockWidgetArea, trackerDocker);

	_dockerMenu->addAction(trackerDocker->toggleViewAction());
}

void MainWindow::createPlayerPanel()
{
	QHBoxLayout* widgetLayout = new QHBoxLayout();
	QVBoxLayout* viewLayout = new QVBoxLayout();
	
	_labelTime = new QLabel("TimeStamp:");
	_slider = new QSlider(Qt::Orientation::Horizontal);

	QHBoxLayout* timeLayout = new QHBoxLayout();
	timeLayout->addWidget(_labelTime);
	timeLayout->addStretch();

	QPushButton* btnGoTime = new QPushButton("Go Time");
	QPushButton* btnGoFrame = new QPushButton("Go Frame");

	_linTargetTime = new QLineEdit();
	_linTargetTime->setInputMask("99:99:99");
	_linTargetTime->setMaximumWidth(60);
	_linTargetTime->setText("00:00:00");

	_linTargetFrame = new QLineEdit();
	_linTargetFrame->setInputMask("99999");
	_linTargetFrame->setMaximumWidth(60);
	_linTargetFrame->setText("0");

	timeLayout->addWidget(_linTargetTime);
	timeLayout->addWidget(btnGoTime);

	QHBoxLayout* frameLayout = new QHBoxLayout();
	_labelFrame = new QLabel("FrameIndex:");
	frameLayout->addWidget(_labelFrame);
	frameLayout->addStretch();

	frameLayout->addWidget(_linTargetFrame);
	frameLayout->addWidget(btnGoFrame);

	_btnPlay = new QPushButton("Play");
	_btnSlow = new QPushButton("Slow");

	timeLayout->addWidget(_btnPlay);
	frameLayout->addWidget(_btnSlow);


	viewLayout->addLayout(timeLayout);
	viewLayout->addLayout(frameLayout);
	viewLayout->addWidget(_slider);

	connect(_slider, SIGNAL(sliderMoved(int)), this, SLOT(seekVideo(int)));
	connect(btnGoTime, SIGNAL(clicked()), this, SLOT(goTime()));
	connect(btnGoFrame, SIGNAL(clicked()), this, SLOT(goFrame()));
	connect(_btnPlay, SIGNAL(clicked()), this, SLOT(playOrPauseVideo()));
	connect(_btnSlow, SIGNAL(clicked()), this, SLOT(slowDown()));

	QWidget* playerWidget = new QWidget();
	playerWidget->setMinimumWidth(300);
	playerWidget->setMaximumHeight(150);
	playerWidget->setMinimumHeight(150);
	playerWidget->setLayout(viewLayout);
	playerWidget->show();


	QDockWidget* playerDocker = new QDockWidget(tr("Player"), this);
	playerDocker->setWidget(playerWidget);	
	addDockWidget(Qt::BottomDockWidgetArea, playerDocker);

	_dockerMenu->addAction(playerDocker->toggleViewAction());
}

void MainWindow::createProjectPanel()
{
    _treeModel = new TreeModel();
	//_treeModel = new QStandardItemModel();
    _treeView = new QTreeView();
	_treeView->setModel(_treeModel);
	_treeView->setWindowTitle(QObject::tr("Project Tree Window"));
	_treeView->setMinimumWidth(220);
	_treeView->setHeaderHidden(true);

    connect(_treeView,SIGNAL(doubleClicked(const QModelIndex &)),this,SLOT(treeDoubleClicked(const QModelIndex &)));

	QDockWidget* projectDocker = new QDockWidget(tr("Project"), this);
	projectDocker->setWidget(_treeView);
		
	addDockWidget(Qt::LeftDockWidgetArea, projectDocker);

	_dockerMenu->addAction(projectDocker->toggleViewAction());
}

void MainWindow::updateActiveSequence()
{
	if (!_project->getActiveSequence())
		return;

	_view->reset();

	Sequence* sequence = _project->getActiveSequence();
	connect(sequence, SIGNAL(timeStampUpdated()), this, SLOT(updateTimeStamp()));

	_controller->playVideo();	

	_btnPlay->setText("Pause");

	::Sleep(200);
	goFrameIndex(0);
}

void MainWindow::updateTree()
{
	if (_treeModel)
	{
		_treeModel->update(_project);
		_treeView->expandAll();
	}
}

void MainWindow::treeDoubleClicked(const QModelIndex& index)
{
    QStandardItem* item = _treeModel->itemFromIndex(index);

    QVariant data = item->data();
    int usrType = data.userType();
    int seqType = qMetaTypeId<Sequence*>();
    int clsType = qMetaTypeId<Class*>();
    int prjType = qMetaTypeId<Project*>();

    if( usrType == prjType )
    {

    }
    else if( usrType == seqType )
    {
        Sequence* sequence = data.value<Sequence*>();

        if( sequence != _project->getActiveSequence())
        {
            _project->setActiveSequence(sequence);

			updateActiveSequence();

			updateTree();
			updateTable();
        }
    }
    else if( usrType == clsType )
    {
        Class* cls = data.value<Class*>();
        if( cls != _project->getActiveClass())
        {
            _project->setActiveClass(cls);
            updateTree();
            updateTable();
        }
    }
}

void MainWindow::addClass()
{
	bool ok;
	QString text = QInputDialog::getText(this, tr("Add Class"),
		tr("Please Enter the new Class Name."), QLineEdit::Normal,
		QString("Default"), &ok);
	if (ok && !text.isEmpty())
	{
		_project->addClass(text.toStdString());
		updateTree();
	}
}

void MainWindow::help()
{
	QDesktopServices::openUrl(QUrl("http://gitee.com/ctguhzy/VideoAnnotator"));
}

void MainWindow::about()
{
	QMessageBox msgBox;
	msgBox.setText("VideoAnnotator");
	msgBox.setInformativeText("This is a tool developped by China Three Gorges University. If you have any question about this tool, please refer the help page or contact with us.");
	msgBox.setStandardButtons(QMessageBox::Ok);
	msgBox.setDefaultButton(QMessageBox::Ok);
	msgBox.exec();
}

void MainWindow::updateSelectedTableRows()
{
	_tableView->clearSelection();

	for (int i = 0; i < _tableViewModel->rowCount(); i++)
	{
		QStandardItem* item = _tableViewModel->item(i, 0);

		QVariant data = item->data();

		TrackedObject* obj = data.value<TrackedObject*>();

		if (obj->isSelected())
		{
			_tableView->selectRow(i);
		}
	}
}

void MainWindow::hideSelectedObjects()
{
	Sequence* seq = _project->getActiveSequence();
	std::vector<TrackedObject*>* objs = seq->getTrackedObjects();

	for (int i = 0; i < objs->size(); i++)
	{
		TrackedObject* obj = objs->at(i);
		if (obj->isSelected())
		{
			obj->deselect();
			obj->setVisible(false);
		}
	}

	_btnShowAllObjects->setEnabled(true);
	_actShowAllObjects->setEnabled(true);

	_btnHideSelectedObjects->setEnabled(false);
	_actHideSelectedObjects->setEnabled(false);

	_view->update();
}

void MainWindow::hideUnSelectedObjects()
{
	Sequence* seq = _project->getActiveSequence();
	std::vector<TrackedObject*>* objs = seq->getTrackedObjects();

	for (int i = 0; i < objs->size(); i++)
	{
		TrackedObject* obj = objs->at(i);
		if (obj->isSelected())
			obj->setVisible(true);
		else
			obj->setVisible(false);
	}

	_btnHideUnSelectedObjects->setEnabled(false);
	_actHideUnSelectedObjects->setEnabled(false);

	_btnShowAllObjects->setEnabled(true);
	_actShowAllObjects->setEnabled(true);

	_view->update();
}

void MainWindow::showAllObjects()
{
	Sequence* seq = _project->getActiveSequence();
	std::vector<TrackedObject*>* objs = seq->getTrackedObjects();

	for (int i = 0; i < objs->size(); i++)
	{
		TrackedObject* obj = objs->at(i);
		obj->setVisible(true);
	}

	_btnShowAllObjects->setEnabled(false);
	_actShowAllObjects->setEnabled(false);

	_view->update();
}

void MainWindow::mergeSelectedObjects()
{
	QMessageBox msgBox;
	msgBox.setText("The selected objects in the Object Table will be merged to a single object.");
	msgBox.setInformativeText("Are you sure to merge these objects?");
	msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
	msgBox.setDefaultButton(QMessageBox::Cancel);
	int ret = msgBox.exec();

	if (ret == QMessageBox::Cancel)
		return;

	std::vector<TrackedObject*> selectedObjects;

	QItemSelectionModel* model = _tableView->selectionModel();

	QModelIndexList list = model->selectedRows();

	for (int i = 0; i < list.size(); i++)
	{
		QModelIndex index = list.at(i);

		QStandardItem* item = _tableViewModel->item(index.row(), 0);

		TrackedObject* object = item->data().value<TrackedObject*>();

		selectedObjects.push_back(object);
	}

	if (selectedObjects.size() > 1)
	{
		Sequence* seq = _project->getActiveSequence();
		seq->mergeTrackedObjects(selectedObjects);

		updateTree();
		updateTable();
	}
}

void MainWindow::makeNegativeSampleFrame()
{
	if (_controller)
	{
		_controller->makeNegativeSampleFrame();
		_view->update();
		updateTable();
		updateTree();
	}
}

void MainWindow::importProject()
{
}

void MainWindow::importSequences()
{
}

void MainWindow::onKeySpace()
{
	if (_view)
	{
		if (ViewStatus::VW_STATUS_DISPLAYING == _view->getViewStatus())
		{
			playOrPauseVideo();
		}
		else
		{
			nextFrame();
		}
	}
}

//void MainWindow::zoomArrow()
//{
//	if (ViewStatus::VW_STATUS_DISPLAYING != _view->getViewStatus())
//	{
//		_view->onKeyArrow();
//	}
//}

//void MainWindow::zoomDrag()
//{
//	if (ViewStatus::VW_STATUS_FRAME_DRAGING != _view->getViewStatus())
//	{
//		_view->onKeyDrag();
//	}
//}

void MainWindow::zoomIn()
{
	if (_view)
		_view->zoomIn();
}

void MainWindow::zoomFit()
{
	if (_view)
		_view->zoomFit();
}

void MainWindow::zoomOut()
{
	if (_view)
		_view->zoomOut();
}

void MainWindow::zoomFullScreen()
{
	if (_view)
	{
		_view->setParent(0);
		_view->showFullScreen();
		_view->setFocusPolicy(Qt::StrongFocus);
	}
}

void MainWindow::rects2Objects()
{
	if (_project && _project->getActiveSequence())
	{
		Sequence* sequence = _project->getActiveSequence();
		sequence->rects2Objects();

		updateTable();
		updateTree();
	}
	
}

void MainWindow::keyPressEvent(QKeyEvent* event)
{
	if (event->key() == Qt::Key_A)
		playOrPauseVideo();
	else if (event->key() == Qt::Key_S)
		nextFrame();
	else if (event->key() == Qt::Key_D)
		prevFrame();
	else if (event->key() == Qt::Key_F)
		zoomFit();
	else if (event->key() == Qt::Key_Z)
		rects2Objects();
	else if (event->key() == Qt::Key_X)
		deleteObject();
	else if (event->key() == Qt::Key_C)
		clearRects();
	else if (event->key() == Qt::Key_T)
		startTrack();
	else if (event->key() == Qt::Key_Space)
		nextFrame();
	else if (event->key() == Qt::Key_PageUp)
		zoomIn();
	else if (event->key() == Qt::Key_PageDown)
		zoomOut();
	else if (event->key() == Qt::Key_Delete)
		deleteObject();
}

void MainWindow::trackTypeChanged(int index)
{
	if (index < 2)
	{
		_btnStartTrack->setEnabled(true);
		_cbNetModel->setEnabled(true);
	}
	else
	{
		if (_view->getRects().size() > 0)
			_btnStartTrack->setEnabled(true);
		else
			_btnStartTrack->setEnabled(false);

		_cbNetModel->setEnabled(false);
	}
}
